package simulador;

import eduni.simjava.Sim_entity;
import eduni.simjava.Sim_event;
import eduni.simjava.Sim_from_p;
import eduni.simjava.Sim_port;
import eduni.simjava.Sim_stat;
import eduni.simjava.Sim_system;
import eduni.simjava.distributions.Sim_negexp_obj;
import eduni.simjava.distributions.Sim_normal_obj;
import eduni.simjava.distributions.Sim_uniform_obj;

public class CPU extends Sim_entity {
	private Sim_port in, out;
	private double time = 10;
	private Sim_normal_obj delay;
	private Sim_stat stat;
	private Sim_uniform_obj prob;

	CPU(String name) {
		super(name);
		// Port for receiving events from the source
		in = new Sim_port("In");
		// Port for sending events to disk 1
		out = new Sim_port("Out");
		add_port(in);
		add_port(out);
		stat = new Sim_stat();
		stat.add_measure(Sim_stat.ARRIVAL_RATE);
		stat.add_measure(Sim_stat.QUEUE_LENGTH);
		// stat.add_measure(Sim_stat.RESIDENCE_TIME);
		stat.add_measure(Sim_stat.SERVICE_TIME);
		stat.add_measure(Sim_stat.THROUGHPUT);
		stat.add_measure(Sim_stat.UTILISATION);
		// stat.add_measure(Sim_stat.WAITING_TIME);
		// stat.add_measure("Discarted jobs", Sim_stat.RATE_BASED);
		stat.add_measure("Completed jobs", Sim_stat.RATE_BASED);
		stat.add_measure("Time Response", Sim_stat.INTERVAL_BASED);
		set_stat(stat);
	}

	public CPU(String name, double delayTime, long seed, double time) {
		this(name);
		this.time = time;
		delay = new Sim_normal_obj("delay", delayTime, delayTime * 0.01, seed);
		prob = new Sim_uniform_obj("prob", 0, 10, seed);
		// delay = new Sim_negexp_obj("delay", seed);
	}

	public CPU(String name, double delayTime) {
		this(name);
		this.time = Long.MAX_VALUE;
		delay = new Sim_normal_obj("delay", delayTime, delayTime * 0.01);
		prob = new Sim_uniform_obj("prob", 0, 10);
		// delay = new Sim_negexp_obj("delay", seed);
	}

	public void body() {
		while (Sim_system.running()) {
			Sim_event e = new Sim_event();
			// Get the next event
			sim_get_next(e);
			if (e.get_tag() == -1)
				continue;
			// if (e.get_tag() == 0
			// && (Sim_system.clock() - e.event_time()) > this.time) {
			// // TODO Discart job
			// sim_trace(2, "Job discarted: time("
			// + (Sim_system.clock() - e.event_time()) + ")");
			// stat.update("Discarted jobs", Sim_system.sim_clock());
			// continue;
			// }
			// Get the event's data
			Job job = (Job) e.get_data();
			// if (job.isOk()) {
			if (prob.sample() < 1) {
				// TODO Output job
				sim_process(delay.sample());
				sim_trace(4, "Job(" + e.get_tag() + ") OK");
				stat.update("Completed jobs", Sim_system.sim_clock());
				stat.update("Time Response", job.getTimeBorn(), Sim_system
						.sim_clock());
				// System.out.println(e.get_tag()+" ini:"+job.getTimeBorn()+
				// " fim:"+Sim_system.sim_clock());
				// System.out.println(Sim_system.sim_clock() -
				// job.getTimeBorn());
				continue;
			} else {
				// job.decrementaIteracao();
				// Get data's recurso id
				long idLocker = job.getRecurso();
				// Process the event
				sim_process(delay.sample());
				// sim_process(260);
				sim_trace(4, "Job processed. iterations(" + job.getIterations()
						+ ")");
				// The event has completed service
				sim_completed(e);
				// Even I/O jobs go to disk throw the locker
				// sim_trace(4, "Job sent to Locker" + job.getRecurso());
				sim_trace(4, "Job sent to Disk");
				// sim_schedule(Sim_system.get_entity_id("Locker"
				// + String.valueOf(job.getRecurso())), 0.0, 1, job);
				// sim_schedule(Sim_system.get_entity_id("Locker"
				// + String.valueOf(job.getRecurso())), 0.0, e.get_tag(), job);
				sim_schedule(out, 0.0, e.get_tag(), job);
			}
		}
	}
}
